package pl.s7n.paint.utils;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;

import pl.s7n.paint.DrawingToolInfo;
import pl.s7n.paint.DrawingTools;

public class Utils {

  private static Utils    instance = new Utils();

  public static final int TYPE     = BufferedImage.TYPE_INT_RGB;

  public static DrawingToolInfo defaultTool() {
    DrawingToolInfo tool = new DrawingToolInfo();
    tool.setColor(Color.BLACK);
    tool.setStroke(new BasicStroke());
    tool.setTool(DrawingTools.PENCIL);
    tool.setFont(Font.getFont("Tahoma"));
    return tool;
  }

  public static BufferedImage defaultImage(int width, int height) {
    BufferedImage image = new BufferedImage(width, height, TYPE);
    clearImage(image);
    return image;
  }

  public static Graphics2D clearImage(BufferedImage image) {
    Graphics2D g = image.createGraphics();
//    g.clearRect(0, 0, image.getWidth(), image.getHeight());//TODO
    g.setColor(Color.WHITE);
    g.fillRect(0, 0, image.getWidth(), image.getHeight());
    return g;
  }

  public static Line2D createLine(Point p1, Point p2) {
    return new Line2D.Float(p1.x, p1.y, p2.x, p2.y);
  }

  public static Rectangle2D createRectangle(Point p1, Point p2) {
    return new Rectangle2D.Float(//
        Math.min(p1.x, p2.x), Math.min(p1.y, p2.y), // left upper corner 
        Math.abs(p2.x - p1.x), Math.abs(p2.y - p1.y)); // width & height
  }

  public static Ellipse2D createEllipse(Point p1, Point p2) {
    return new Ellipse2D.Float( //
        Math.min(p1.x, p2.x), Math.min(p1.y, p2.y), // left upper corner 
        Math.abs(p2.x - p1.x), Math.abs(p2.y - p1.y)); // width & height
  }

  public static BufferedImage loadImage(File file) {
    BufferedImage img = null;
    try {
      img = ImageIO.read(file);
    } catch (IOException e) {
      e.printStackTrace();
      showError("Problems encountered while reading file.", e.getMessage());
    }
    return img;
  }

  public static void writeImage(BufferedImage image, File file) {
    try {
      String name = file.getName();
      String ext = name.substring(name.lastIndexOf('.') + 1);
      ImageIO.write(image, ext, file);
    } catch (IOException e) {
      e.printStackTrace();
      showError("Problems encountered while writing to file.", e.getMessage());
    }
  }

  private static void showError(String title, String desc) {
    JOptionPane.showMessageDialog(null, desc, title, JOptionPane.ERROR_MESSAGE);
  }

  public static final FileFilter supportedFileFilter;
  static {
    supportedFileFilter = new FileFilter() {
      @Override
      public boolean accept(File f) {
        return Pattern.matches("^.+\\.(bmp|wbmp|jpg|jpeg|gif|png)$", f.getName().toLowerCase());
      }

      @Override
      public String getDescription() {
        return "Image files: BMP, JPG, JPEG, GIF, PNG, WBMP";
      }
    };
  }

  public static ImageIcon loadImageIcon(String path) {
    URL url = instance.getClass().getClassLoader().getResource(path);
    if (url != null) {
      return new ImageIcon(url);
    } else {
      System.err.println("Couldn't find file: " + path);
      return null;
    }
  }

  public static BufferedImage resizeImage(BufferedImage in, Point newSize) {
    BufferedImage out = defaultImage(newSize.x, newSize.y);
    out.createGraphics().drawRenderedImage(in, new AffineTransform());
    return out;
  }

  public static void setFixedSize(JComponent compo, int x, int y) {
    Dimension size = new Dimension(x, y);
    compo.setMaximumSize(size);
    compo.setPreferredSize(size);
    compo.setSize(size);
  }
  
  public static Point withBorder(Point in, int border) {
    in.translate(border, border);
    return in;
  }
}
